package com.xpc.rpc.provider.handler;

import com.xpc.rpc.common.enums.RpcMsgType;
import com.xpc.rpc.protocol.ProtocolMessage;
import com.xpc.rpc.protocol.header.RpcHeader;
import com.xpc.rpc.protocol.request.RpcRequest;
import com.xpc.rpc.protocol.response.RpcResponse;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Method;
import java.util.Map;

public class RpcProviderHandler extends SimpleChannelInboundHandler<ProtocolMessage<RpcRequest>> {

    private static final Logger LOGGER = LoggerFactory.getLogger(RpcProviderHandler.class);

    private Map<String,Object> handlerMap;

    public RpcProviderHandler(Map<String,Object> handlerMap) {
        this.handlerMap = handlerMap;
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, ProtocolMessage<RpcRequest> protocolMessage) throws Exception {
        RpcHeader rpcHeader = protocolMessage.getRpcHeader();
        RpcRequest request = protocolMessage.getT();
        ProtocolMessage<RpcResponse> protocolResponseMessage = handlerMessage(rpcHeader,request);
        ctx.writeAndFlush(protocolResponseMessage);
    }

    /**
     * 处理请求
     * @param rpcHeader
     * @param request
     */
    private ProtocolMessage<RpcResponse> handlerMessage(RpcHeader rpcHeader, RpcRequest request) {
        ProtocolMessage<RpcResponse> protocolMessage = new ProtocolMessage<RpcResponse>();
        rpcHeader.setMsgType(RpcMsgType.RESPONSE.getType());
        protocolMessage.setRpcHeader(rpcHeader);
        RpcResponse response = new RpcResponse();

        String className = request.getClassName();
        if(!handlerMap.containsKey(className)) {
            throw new RuntimeException("no find class for " + className);
        }
        Object classBean = handlerMap.get(className);
        Class<?> beanClass = classBean.getClass();
        Method method;
        Object result = null;
        try {
            method = beanClass.getMethod(request.getMethodName(), request.getParameterTypes());
            method.setAccessible(true);
            result = method.invoke(classBean,request.getParameters());
            response.setData(result);
            response.setCode(200);
        } catch (Exception e) {
            response.setErrMsg(e.getMessage());
            response.setCode(500);
        }
        protocolMessage.setT(response);
        return protocolMessage;
    }
}
